﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;

namespace SdmxMl.UC
{
    public class RefreshingListBox : ListBox
    {
        private object m_itemOrigineDrag;
        private object m_itemMouseDown;
        public RefreshingListBox()
		{
			InitializeComponent();
			// init des propriétés par défaut
            this.AllowItemMove = true;
		}

        public new void RefreshItem(int index)
        {
            base.RefreshItem(index);
        }

        public new void RefreshItems()
        {
            base.RefreshItems();
        }

        private void InitializeComponent()
        {
            this.AllowDrop = true;
            this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.listBox_MouseDown);
            this.DragOver += new System.Windows.Forms.DragEventHandler(this.listBox_DragOver);
            this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.listbox_MouseMove);
            this.DragDrop += new System.Windows.Forms.DragEventHandler(this.listBox_DragDrop);
            this.DragEnter += new DragEventHandler(listbox_DragEnter);
       //     this.MouseUp += new MouseEventHandler(RefreshingListBox_MouseUp);

        }

        void RefreshingListBox_MouseUp(object sender, MouseEventArgs e)
        {
            object o = GetItemObject(new Point(e.X, e.Y), false);
            if (o != null)
            {
                SelectedItem = null;
                SelectedItem = o;
            }
            
        }
        
        private void listbox_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.Text))
                e.Effect = DragDropEffects.Move;
            else
                e.Effect = DragDropEffects.None;
        }
        private object GetItemObject(Point ex, bool toClient)
        {
            object o = null;
            if (toClient)
                ex = this.PointToClient(ex);
            int index = this.IndexFromPoint(ex);
            if (index >= 0 && index < Items.Count)
                o = Items[index];
            return o;
        }

        private void listBox_MouseDown(object sender, MouseEventArgs e)
        {
            m_itemMouseDown = null;
            // If move authorized and left button pressed
            if (Items.Count > 0 && this.AllowItemMove && e.Button == MouseButtons.Left)
            {
                // récupération du node sous la souris
                m_itemMouseDown = GetItemObject(new Point(e.X, e.Y), false);
            }		
        }

        private void listbox_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            // si déplacements autorisés et pas de drag en cours et bouton gauche appuyé
            if (m_itemMouseDown != null && Items.Count > 0 && this.AllowItemMove && m_itemOrigineDrag == null && e.Button == MouseButtons.Left)
            {
                // récupération du node sous la souris
                object o = GetItemObject(new Point(e.X, e.Y), false);
                // si le même node que celui sur lequel on a cliqué 
                // (sinon, on recommence un drag à chaque passage sur un nouveau node)
                // et que pas un node de premier niveau
                if (m_itemMouseDown == o)
                {
                  //  BeforeNodeMoveEventArgs args = new BeforeNodeMoveEventArgs(nod);
                  //  this.OnBeforeNodeMove(args);
                    if (m_itemMouseDown != null) // !args.Cancel)
                    {
                        // stockage du node à l'origine du drag
                        m_itemOrigineDrag = o;
                        SelectedItem = m_itemOrigineDrag;

                        // on effectue le drag drop
                        this.DoDragDrop("", DragDropEffects.Move);
                        // effacement du trait entre les nodes
                       // this.EffaceTrait();
                        // on met à null le node à l'origine du grag
                        m_itemOrigineDrag = null;
                    }
                }
            }
        }

        private void listBox_DragOver(object sender, DragEventArgs e)
        {
            // récupération du node sous la souris
            object o = GetItemObject(new Point(e.X, e.Y), true);
            // si un node sélectionné et que ce node est dans la même branche que celui d'origine
            // et que ce n'est pas le node d'origine
            if (o != null  && o != m_itemOrigineDrag)
            {
                // alors drop autorisé
                e.Effect = DragDropEffects.Move;
                // dessin d'un trait
            //    this.DessineTrait(nod);
            }
            else
            {
                // sinon, drop refusé
                e.Effect = DragDropEffects.None;
             //   this.EffaceTrait();
            }

        }

        private void listBox_DragDrop(object sender, DragEventArgs e)
        {
            Point point = this.PointToClient(new Point(e.X, e.Y));
            int index = this.IndexFromPoint(point);

            if (index >= 0 && Items[index] != m_itemMouseDown)
            {
                this.Items.Remove(m_itemMouseDown);
                if (index < Items.Count)
                    this.Items.Insert(index, m_itemMouseDown);
                else
                    this.Items.Add(m_itemMouseDown);

            }

            object o = SelectedItem;
            if (m_itemMouseDown == null)
                m_itemMouseDown = 0;
            if (m_itemMouseDown != null)
            {
                SelectedItem = null;
                SelectedItem = m_itemMouseDown;
            }
        }

        #region Properties

        private bool m_allowItemMove;

        [Description("Autorize or not to move items in listbox")]
        [DefaultValue(true)]
        public bool AllowItemMove
        {
            get
            {
                return m_allowItemMove;
            }
            set
            {
                m_allowItemMove = value;
            }
        }

        #endregion

    } 
}
